#include "tcp_server.h"
#include <stdio.h>
#include <iostream>
#include "tcp_connection.h"

namespace rr {
namespace nio {


TcpServer::TcpServer(EventLoop::Sptr loop, const EventLoopThreadPool::Sptr thread_pool)
: loop_(loop)
, work_thread_pool_(thread_pool)
, acceptor_(loop->GetIoContextRef())
{
    connection_cb_ = std::bind(&NetCallback::DefualtConnectionCallback, std::placeholders::_1);
}

TcpServer::~TcpServer()
{

}

int32_t TcpServer::Start(int32_t backlog)
{

    try
    {
        //ip port ipv4 or ipv6
        boost::asio::ip::tcp::endpoint ep(boost::asio::ip::make_address("0.0.0.0"), 16789);

        acceptor_.open(ep.protocol());
        acceptor_.bind(ep);
        acceptor_.listen(backlog);

        DoAccept();
    }
    catch(const std::exception& e)
    {
        printf("TcpServer::Start exception: %s\n", e.what());
        return -1;
    }
    
    return 0;
}

int32_t TcpServer::Stop()
{
    auto self = shared_from_this();
    acceptor_.close();

    return 0;
}

void TcpServer::DoAccept()
{
    EventLoop::Sptr loop = GetWorkLoop();
    auto self = shared_from_this();

    acceptor_.async_accept(loop->GetIoContextRef(),
        [self, loop] (boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {
        self->OnAccept(ec, socket, loop);
    });
}

void TcpServer::OnAccept(const boost::system::error_code &ec, boost::asio::ip::tcp::socket& socket, EventLoop::Sptr loop)
{
    if (ec) {
        printf("DoAccept ec: %s\n", ec.message().c_str());
        return;
    }

    std::cout << "TcpServer::OnAccept tid=" << std::this_thread::get_id() << std::endl;
    auto conn = std::make_shared<TcpConnection>(loop, socket);
    conn->SetConnectionCallback(connection_cb_);
    loop->RunInLoop(std::bind(&TcpConnection::SetConnectSuccess, conn));

    DoAccept();

    return;
}

EventLoop::Sptr TcpServer::GetWorkLoop()
{
    EventLoop::Sptr loop = loop_;
    if(work_thread_pool_.get()) {
        loop = work_thread_pool_->GetNextLoop();
    }

    return loop;
}

} //namespace 
} //namespace 